Clear the dataset's whole hash index with one range tombstone over its CF_BLOCK_HASHES prefix, then delete all chunk metadata and the label in a single transaction. The range-delete stays outside the tx (RocksDB forbids delete_range inside a transaction); a crash between the two leaves chunks without index entries, which 404 until re-indexed, not corruption.
Keeps memory bounded (no delete_cf per block) while making the metadata deletion all-or-nothing again, and re-takes the optimistic label lock. Adds BlockHashIndexKey::dataset_range for the prefix bounds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Lets consumers resolve a bare block hash to its block number. Today the hash is only buried inside each chunk's Arrow
hashcolumn, so the only way to look it up is a linear scan (~0.1–0.6s, and worse as retention grows). This adds a proper index for an O(1) point lookup, plus an HTTP endpoint to use it.The motivation: services that receive a raw hash (from logs, fork events, external sources) need to map it back to a block number to keep working with the standard
/streamAPIs.What's new
hash → block numberper dataset, kept up to date automatically as chunks are ingested, forked, and pruned. Enabled for EVM datasets for now (easy to extend to other chains later).GET /datasets/{id}/hashes/{hash}/block, returning{number, hash}or404if the hash isn't found.Rollout notes
404until those chunks roll off via retention. Worth calling out in release notes.Testing
Unit tests in
sqd-storagecover ingest, fork, retention, dataset deletion, and confirm compaction leaves the index intact. Manual HTTP smoke against a live hotblocks instance still recommended.🤖 Generated with Claude Code